import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { Donut, HBars, StackedBars } from '@/components/charts/charts'; import { Block, EventsList, ExternalLink, HeroFacts, KpiStrip, PlannedUnavailable, Tag, entityMetadata } from '@/components/entities/shared'; import { ConstellationsMiniTable, LaunchesTable, SatellitesTable, SitesTable } from '@/components/entities/tables'; import { Container } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { ApiError, api } from '@/lib/api'; import { fmtDate, fmtDateTime, fmtInt, num, titleCase } from '@/lib/format'; import { MISSION_LABELS, ORBIT_CLASS_COLORS, SITE_URL, STATUS_COLORS, routes } from '@/lib/site'; import type { OperatorDetail } from '@/lib/types'; type Props = { params: Promise<{ slug: string }> }; async function load(slug: string): Promise<{ d: OperatorDetail; generatedAt: string } | null> { try { const res = await api.operator(slug); return { d: res.data, generatedAt: res.meta.generated_at }; } catch (e) { if (e instanceof ApiError && e.notFound) return null; throw e; } } export async function generateMetadata({ params }: Props): Promise { const { slug } = await params; const r = await load(slug).catch(() => null); if (!r) return { title: 'Operator not found', robots: { index: false } }; const { d } = r; return entityMetadata({ title: `${d.name} — ${fmtInt(d.active_payloads)} active satellites, ${titleCase(d.kind).toLowerCase()}${d.country_name ? ` (${d.country_name})` : ''}`, description: `${d.name} operates ${fmtInt(d.active_payloads)} active payloads out of ${fmtInt(d.total_payloads)} launched across ${fmtInt(d.launches)} launches since ${fmtDate(d.first_launch)}. Fleet by status, orbit and mission, constellations, launch history and growth.`, path: routes.operator(d.slug), }); } export default async function OperatorPage({ params }: Props) { const { slug } = await params; const r = await load(slug); if (!r) notFound(); const { d, generatedAt } = r; const statusData = d.status_distribution.map((s) => ({ label: titleCase(s.status.toLowerCase()), value: num(s.count) ?? 0, color: STATUS_COLORS[s.status] ?? 'var(--other)' })).filter((x) => x.value > 0).sort((a, b) => b.value - a.value); const orbitData = d.orbit_distribution.map((o) => ({ label: o.orbit_class, value: num(o.count) ?? 0, color: ORBIT_CLASS_COLORS[o.orbit_class] ?? 'var(--other)' })).filter((x) => x.value > 0).sort((a, b) => b.value - a.value); const missionData = d.mission_distribution.map((m) => ({ label: MISSION_LABELS[m.mission_type] ?? titleCase(m.mission_type), value: num(m.count) ?? 0 })).filter((x) => x.value > 0).sort((a, b) => b.value - a.value); const growth = d.growth.map((g) => { const launched = num(g.launched) ?? 0; const still = Math.min(launched, num(g.still_active) ?? 0); return { x: g.year, still_active: still, retired: Math.max(0, launched - still) }; }); const jsonLd = { '@context': 'https://schema.org', '@type': 'Organization', name: d.name, alternateName: d.aliases, url: d.official_url ?? undefined, sameAs: d.official_url ? [d.official_url] : undefined, address: d.country_name ? { '@type': 'PostalAddress', addressCountry: d.country_code ?? d.country_name } : undefined, mainEntityOfPage: `${SITE_URL}${routes.operator(d.slug)}`, }; return (